#include "ray.h"
#include "material.h"
#include "light.h"

// Apply the phong model to this point on the surface of the object, returning
// the color of that point.
vec3f Material::shade( Scene *scene, const ray& r, const isect& i ) const
{
	// YOUR CODE HERE

	// For now, this method just returns the diffuse color of the object.
	// This gives a single matte color for every distinct surface in the
	// scene, and that's it.  Simple, but enough to get you started.
	// (It's also inconsistent with the phong model...)

	// Your mission is to fill in this method with the rest of the phong
	// shading model, including the contributions of all the light sources.
    // You will need to call both distanceAttenuation() and shadowAttenuation()
    // somewhere in your code in order to compute shadows and light falloff.
	
	// contribution soley from ambient light
	vec3f ambient(ka[0] * scene->ambientLightColor[0], ka[1] * scene->ambientLightColor[1], ka[2] * scene->ambientLightColor[2]);

	// contribution from all lightsources
	vec3f lightSources(0.0f, 0.0f, 0.0f);
	for (Scene::cliter l = scene->beginLights(); l != scene->endLights(); l++) {

		// float distAtten = 1.0f; // assume distance of light source doesn't affect
		float distAtten = (*l)->distanceAttenuation(r.at(i.t));
		vec3f shadowAtten = (*l)->shadowAttenuation(r.at(i.t));
		if (kt * kt != 0 )
			shadowAtten -= kt;

		// light direction
		vec3f lightDirection = (*l)->getDirection(r.at(i.t)).normalize();
		// cos n
		float ratio = fabs(lightDirection.dot(i.N.normalize()));
		
		// Compute the diffusion term //
		vec3f diffusion = kd * ratio;
		// cout << diffusion[0] << "," << diffusion[1] << "," << diffusion[2] << endl;

		// Compute the specular term //
			// R
		vec3f reflected = (lightDirection - 2 * (lightDirection - ratio * i.N.normalize())).normalize();
			// V
		float phi = (-r.getDirection().normalize()).dot(reflected);
		float raised = pow(phi, (float)this->shininess * 100.f);
		if (!(raised == raised)) raised = 0.0f;
		vec3f specular = raised * ks; 	

		// take into account distance attenuation
		vec3f temp = (diffusion + specular) * (distAtten);
		// take into account shadow attenuation
		for (int q = 0; q < 3; q++) temp[q] *= shadowAtten[q];
		
		vec3f col = (*l)->getColor(r.at(i.t));
		lightSources += vec3f(temp[0] * col[0], temp[1] * col[1], temp[2] * col[2]);

		
	}
	
	return ke + ambient + lightSources;
	// return kd;
}
